package com.adv.ems.filters.report.after;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.adv.ems.constants.EmsConst;
import com.adv.ems.db.entity.CollectPointDO;
import com.adv.ems.db.entity.EnergyDataCumulateReportHourDO;
import com.adv.ems.enums.CollectPointWarningTypeEnum;
import com.adv.ems.filters.EnergyDataBaseFilter;
import com.adv.ems.filters.dto.FilterParam;
import com.adv.ems.filters.report.dto.ReportHourPoolDTO;
import com.adv.ems.manager.CollectPointManager;
import com.adv.ems.manager.EnergyDataCumulateReportHourManager;
import com.adv.ems.model.vo.ResultVO;
import com.adv.ems.service.WarningService;
import com.adv.ems.utils.ScriptUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class HourVirtualPointReportAfterFilter extends EnergyDataBaseFilter<ReportHourPoolDTO, Boolean> {
    @Resource
    CollectPointManager collectPointManager;
    @Resource
    EnergyDataCumulateReportHourManager energyDataCumulateReportHourManager;
    @Resource
    WarningService warningService;

    @Override
    protected String getFilterName() {
        return "虚拟采集点报表小时数据统计";
    }

    @Override
    protected double getOrder() {
        return 1;
    }

    @Override
    protected boolean isBefore() {
        return false;
    }

    @Override
    protected String getType() {
        return ReportHourPoolDTO.class.getName();
    }

    @Override
    protected ResultVO<Boolean> handle(FilterParam<ReportHourPoolDTO> param) {
        Map<Long, Set<Long>> virtualPointRelationPointIds = new HashMap<>();
        Set<ReportHourPoolDTO> virtualHourPools = buildVirtualReportHour(param.getList(), virtualPointRelationPointIds);
        param.getList().addAll(virtualHourPools);
        virtualHourPools.forEach(r -> dealEachPointHour(r, virtualPointRelationPointIds));
        return ResultVO.success(true);
    }

    private Set<ReportHourPoolDTO> buildVirtualReportHour(List<ReportHourPoolDTO> receiveReportHours, Map<Long, Set<Long>> virtualPointRelationPointIds) {
        Map<Long, Set<Long>> pointRelationVirtualPointIds = new HashMap<>();
        collectPointManager.getAllMap().values().forEach(p -> {
            String isVirtual = p.getVirtual();
            if (EmsConst.YES.equals(isVirtual)) {
                Set<Long> relatePointIds = ScriptUtil.getVirtualPointRelatePointIds(p.getComputeScript());
                virtualPointRelationPointIds.put(p.getId(), relatePointIds);
                relatePointIds.forEach(id -> {
                    Set<Long> orDefault = pointRelationVirtualPointIds.getOrDefault(id, new HashSet<>());
                    orDefault.add(p.getId());
                    pointRelationVirtualPointIds.put(id, orDefault);
                });
            }
        });
        Set<ReportHourPoolDTO> virtualHourPool = new HashSet<>();
        receiveReportHours.forEach(h -> {
            Set<Long> virtualPointIds = pointRelationVirtualPointIds.get(h.getPointId());
            if (virtualPointIds != null) {
                virtualPointIds.forEach(virtualPointId -> {
                    ReportHourPoolDTO reportHour = new ReportHourPoolDTO();
                    reportHour.setPointId(virtualPointId);
                    reportHour.setTime(h.getTime());
                    reportHour.setId(-1L);
                    reportHour.setCreateTime(new Date());
                    reportHour.setUpdateTime(new Date());
                    virtualHourPool.add(reportHour);
                });
            }
        });
        return virtualHourPool;
    }

    private void dealEachPointHour(ReportHourPoolDTO reportHour, Map<Long, Set<Long>> virtualPointRelationPointIds) {
        log.info("统计采集点ID【{}】统计时间：【{}】开始", reportHour.getPointId(), DateUtil.formatDateTime(reportHour.getTime()));
        Set<Long> realPointIds = virtualPointRelationPointIds.get(reportHour.getPointId());
        Map<Long, EnergyDataCumulateReportHourDO> hourReportMap = energyDataCumulateReportHourManager
                .getDataByPointIdsTime(realPointIds, reportHour.getTime())
                .stream()
                .collect(Collectors.toMap(EnergyDataCumulateReportHourDO::getCollectPointId, d -> d, (d1, d2) -> d2));
        if (hourReportMap.size() != realPointIds.size()) {
            String msg = String.format("虚拟采集点【id：%s】拉取对应真实采集点数量不匹配【理想：%s，实际：%s】", reportHour.getPointId(), realPointIds, hourReportMap.keySet());
            log.warn(msg);
            warningService.pushCollectPointWarning(null, reportHour.getPointId(), CollectPointDO.class, CollectPointWarningTypeEnum.EXCEPTION_DATA, JSONUtil.toJsonStr(reportHour), msg);
        }else {
            CollectPointDO point = collectPointManager.getAllMap().get(reportHour.getPointId());
            EnergyDataCumulateReportHourDO data = new EnergyDataCumulateReportHourDO();
            data.setCollectPointId(reportHour.getPointId());

            Map<Long, Double> lastRealValueMap = new HashMap<>();
            Map<Long, Double> realValueMap = new HashMap<>();
            Map<Long, Double> standValueMap = new HashMap<>();
            Map<Long, Double> cashValueMap = new HashMap<>();
            hourReportMap.forEach((key, value) -> {
                lastRealValueMap.put(key, value.getLastRealValue());
                realValueMap.put(key, value.getIncreaseRealValue());
                standValueMap.put(key, value.getIncreaseStandValue());
                cashValueMap.put(key, value.getIncreaseCashValue());
            });
            data.setLastRealValue(ScriptUtil.getVirtualValue(lastRealValueMap, point));
            data.setIncreaseRealValue(ScriptUtil.getVirtualValue(realValueMap, point));
            data.setIncreaseStandValue(ScriptUtil.getVirtualValue(standValueMap, point));
            data.setIncreaseCashValue(ScriptUtil.getVirtualValue(cashValueMap, point));
            data.setColDate(reportHour.getTime());
            data.setCreateTime(new Date());
            energyDataCumulateReportHourManager.insertData(data);
            if (point.getLastUploadTime() == null || point.getLastUploadTime().before(data.getColDate())) {
                point.setLastUploadTime(data.getColDate());
                point.setLastUploadRealValue(data.getLastRealValue());
                collectPointManager.updateLastUploadInfo(point.getId(), point.getLastUploadTime(), point.getLastUploadRealValue());
            }
        }
        log.info("统计采集点ID【{}】统计时间：【{}】结束", reportHour.getPointId(), DateUtil.formatDateTime(reportHour.getTime()));
    }
}
